﻿#include "app_cdc.h"

#include "app_usb.h"
#include "cherry_rb.h"
#include "dap_config.h"
#include "gd32f4xx_libopt.h"
#include "misc_bit_band.h"
#include "usbd_cdc.h"
#include "usbd_cdc_acm.h"
#include "usbd_core.h"

#define CDC_UART_BUFF_SIZE (8192UL)  // 只能是2的整数次幂

static uint8_t usb_rx_buff[DAP_PACKET_SIZE];  // USB接收缓冲
static uint8_t usb_tx_buff[DAP_PACKET_SIZE];  // USB发送缓冲

static volatile uint8_t usbrx_idle_flag = 0;
static volatile uint8_t usbtx_idle_flag = 0;
static volatile uint8_t uarttx_idle_flag = 0;

static rb_t uart_tx_rb;  // 串口发送
static rb_t uart_rx_rb;  // 串口接收
uint8_t uart_tx_rb_buff[CDC_UART_BUFF_SIZE];
uint8_t uart_rx_rb_buff[CDC_UART_BUFF_SIZE];

/* 存储串口配置参数 */
static struct cdc_line_coding cdc_conf = {  //
    .dwDTERate = 115200,                    //
    .bCharFormat = 0,                       //
    .bDataBits = 8,                         //
    .bParityType = 0};

/**
 * @brief cdc串口初始化
 *
 */
void APP_CDC_Init(void) {
    rcu_periph_clock_enable(RCU_UART3);
    rcu_periph_clock_enable(RCU_UART4);

    rb_init(&uart_rx_rb, (uint8_t *)uart_rx_rb_buff, CDC_UART_BUFF_SIZE);
    rb_init(&uart_tx_rb, (uint8_t *)uart_tx_rb_buff, CDC_UART_BUFF_SIZE);

    /* UART3 ******************************************************************/

    usart_deinit(UART3);
    usart_word_length_set(UART3, USART_WL_8BIT);
    usart_parity_config(UART3, USART_PM_NONE);
    usart_stop_bit_set(UART3, USART_STB_1BIT);
    usart_data_first_config(UART3, USART_MSBF_LSB);
    usart_oversample_config(UART3, USART_OVSMOD_8);
    usart_baudrate_set(UART3, 115200);

    usart_hardware_flow_cts_config(UART3, USART_CTS_DISABLE);
    usart_hardware_flow_rts_config(UART3, USART_RTS_DISABLE);
    usart_transmit_config(UART3, USART_TRANSMIT_DISABLE);
    usart_receive_config(UART3, USART_RECEIVE_DISABLE);

    usart_interrupt_enable(UART3, USART_INT_RBNE);  // 接收中断
    // usart_interrupt_enable(UART3, USART_INT_IDLE);
    usart_receive_config(UART3, USART_RECEIVE_ENABLE);  // 只收
    usart_enable(UART3);
    nvic_irq_enable(UART3_IRQn, 0U, 3U);

    /* UART4 ******************************************************************/

    usart_deinit(UART4);
    usart_word_length_set(UART4, USART_WL_8BIT);
    usart_parity_config(UART4, USART_PM_NONE);
    usart_stop_bit_set(UART4, USART_STB_1BIT);
    usart_data_first_config(UART4, USART_MSBF_LSB);
    usart_oversample_config(UART4, USART_OVSMOD_8);
    usart_baudrate_set(UART4, 115200);

    usart_hardware_flow_cts_config(UART4, USART_CTS_DISABLE);
    usart_hardware_flow_rts_config(UART4, USART_RTS_DISABLE);
    usart_transmit_config(UART4, USART_TRANSMIT_DISABLE);
    usart_receive_config(UART4, USART_RECEIVE_DISABLE);

    usart_interrupt_enable(UART4, USART_INT_TC);          // 发送完成中断
    usart_transmit_config(UART4, USART_TRANSMIT_ENABLE);  // 只发
    usart_enable(UART4);
    nvic_irq_enable(UART4_IRQn, 0U, 3U);
}

/**
 * @brief 设置串口参数，CherryUSB内部调用
 *
 * @param busid
 * @param intf
 * @param line_coding
 */
void usbd_cdc_acm_set_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding) {
    /*******************************************************************************/
    /* Line Coding Structure */
    /*-----------------------------------------------------------------------------*/
    /* Offset | Field       | Size | Value  | Description */
    /* 0      | dwDTERate   |   4  | Number |Data terminal rate, in bits per second*/
    /* 4      | bCharFormat |   1  | Number | Stop bits */
    /*                                        0 - 1 Stop bit */
    /*                                        1 - 1.5 Stop bits */
    /*                                        2 - 2 Stop bits */
    /* 5      | bParityType |  1   | Number | Parity */
    /*                                        0 - None */
    /*                                        1 - Odd */
    /*                                        2 - Even */
    /*                                        3 - Mark */
    /*                                        4 - Space */
    /* 6      | bDataBits  |   1   | Number Data bits (5, 6, 7, 8 or 16).*/
    /*******************************************************************************/

    if (busid == 0) {
        usart_disable(UART3);
        usart_disable(UART4);

        usart_baudrate_set(UART3, line_coding->dwDTERate); /* 波特率 */
        usart_baudrate_set(UART4, line_coding->dwDTERate); /* 波特率 */

        uint32_t uart_stb;
        switch (line_coding->bCharFormat) {
            case 0:
                uart_stb = USART_STB_1BIT;
                break;
            case 2:
                uart_stb = USART_STB_2BIT;
                break;
            default:
                uart_stb = USART_STB_1BIT; /* UART3只支持1/2 */
                break;
        }
        usart_stop_bit_set(UART3, uart_stb); /* 停止位 */
        usart_stop_bit_set(UART4, uart_stb); /* 停止位 */

        uint32_t uart_par;
        switch (line_coding->bParityType) {
            case 0:
                uart_par = USART_PM_NONE;
                break;
            case 1:
                uart_par = USART_PM_ODD;
                break;
            case 2:
                uart_par = USART_PM_EVEN;
                break;
            default:
                uart_par = USART_PM_NONE; /* UART3只支持NONE/ODD/EVEN */
                break;
        }
        usart_parity_config(UART3, uart_par); /* 校验位 */
        usart_parity_config(UART4, uart_par); /* 校验位 */

        uint32_t uart_bits;
        switch (line_coding->bParityType) {
            case 8:
                uart_bits = USART_WL_8BIT;
                break;
            case 9:
                uart_bits = USART_WL_9BIT;
                break;
            default:
                uart_bits = USART_WL_8BIT; /* UART3只支持8/9 */
                break;
        }
        usart_word_length_set(UART3, uart_bits); /* 字长 */
        usart_word_length_set(UART4, uart_bits); /* 字长 */

        usart_enable(UART3);
        usart_enable(UART4);
    }

    cdc_conf.dwDTERate = line_coding->dwDTERate;
    cdc_conf.bDataBits = line_coding->bDataBits;
    cdc_conf.bParityType = line_coding->bParityType;
    cdc_conf.bCharFormat = line_coding->bCharFormat;
}

/**
 * @brief 获取串口参数，CherryUSB内部调用
 *
 * @param busid
 * @param intf
 * @param line_coding
 */
void usbd_cdc_acm_get_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding) {
    line_coding->dwDTERate = cdc_conf.dwDTERate;
    line_coding->bDataBits = cdc_conf.bDataBits;
    line_coding->bParityType = cdc_conf.bParityType;
    line_coding->bCharFormat = cdc_conf.bCharFormat;
}

/**
 * @brief 发送停止，CherryUSB内部调用
 *
 * @param busid
 * @param intf
 */
void usbd_cdc_acm_send_break(uint8_t busid, uint8_t intf) {
    //
}

/**
 * @brief 发给PC结束后的回调函数
 *
 * @param busid
 * @param ep
 * @param nbytes
 */
void APP_CDC_InCallback(uint8_t busid, uint8_t ep, uint32_t nbytes) {
    if ((nbytes % DAP_PACKET_SIZE) == 0 && nbytes) {
        usbd_ep_start_write(0, CDC_IN_EP, NULL, 0);
    } else {
        uint32_t size = rb_get_used(&uart_rx_rb);
        if (size > 0) {
            if (size > DAP_PACKET_SIZE) {
                size = DAP_PACKET_SIZE;
            }

            rb_read(&uart_rx_rb, (uint8_t *)usb_tx_buff, size);
            usbd_ep_start_write(0, CDC_IN_EP, (uint8_t *)usb_tx_buff, size);
        } else {
            usbtx_idle_flag = 1;
        }
    }
}

/**
 * @brief 从PC接收的回调函数
 *
 * @param busid
 * @param ep
 * @param nbytes
 */
void APP_CDC_OutCallback(uint8_t busid, uint8_t ep, uint32_t nbytes) {
    rb_write(&uart_tx_rb, (uint8_t *)usb_rx_buff, nbytes);

    if (rb_get_free(&uart_tx_rb) >= DAP_PACKET_SIZE) {
        usbd_ep_start_read(0, CDC_OUT_EP, (uint8_t *)usb_rx_buff, DAP_PACKET_SIZE);
    } else {
        usbrx_idle_flag = 1;
    }
}

/**
 * @brief 开始接收
 *
 */
void APP_CDC_StartRead(void) {
    usbtx_idle_flag = 1;
    uarttx_idle_flag = 1;
    usbrx_idle_flag = 1;
}

/**
 * @brief 循环处理
 *
 */
void APP_CDC_Handle(void) {
    /* EP_IN轮询 */
    if (usbtx_idle_flag) {
        uint32_t size = rb_get_used(&uart_rx_rb);
        if (size > 0) {
            usbtx_idle_flag = 0;

            if (size > DAP_PACKET_SIZE) {
                size = DAP_PACKET_SIZE;
            }

            rb_read(&uart_rx_rb, (uint8_t *)usb_tx_buff, size);
            usbd_ep_start_write(0, CDC_IN_EP, (uint8_t *)usb_tx_buff, size);
        }
    }

    /* 串口发送轮询  */
    if (uarttx_idle_flag) {
        if (rb_get_used(&uart_tx_rb)) {
            uarttx_idle_flag = 0;
            uint8_t data = 0;

            if (rb_read_byte(&uart_tx_rb, &data)) {
                usart_data_transmit(UART4, data);  // 启动发送
            }
        }
    }

    /* EP_OUT轮询 */
    if (usbrx_idle_flag) {
        if (rb_get_free(&uart_tx_rb) >= DAP_PACKET_SIZE) {
            usbrx_idle_flag = 0;
            usbd_ep_start_read(0, CDC_OUT_EP, (uint8_t *)usb_rx_buff, DAP_PACKET_SIZE);
        }
    }
}

void UART3_IRQHandler(void) {
    // if (usart_interrupt_flag_get(UART3, USART_INT_FLAG_IDLE)) {
    //     usart_data_receive(UART3);
    // }

    /* 接收中断 */
    if (usart_interrupt_flag_get(UART3, USART_INT_FLAG_RBNE)) {
        uint8_t data = usart_data_receive(UART3);
        rb_write_byte(&uart_rx_rb, data);
        // 标志位自动清零
    }
}

void UART4_IRQHandler(void) {
    static uint8_t data;

    /* 发送中断 */
    if (usart_interrupt_flag_get(UART4, USART_INT_FLAG_TC)) {
        usart_interrupt_flag_clear(UART4, USART_INT_FLAG_TC);

        if (rb_read_byte(&uart_tx_rb, &data)) {
            usart_data_transmit(UART4, data);
        } else {
            uarttx_idle_flag = 1;
        }
    }
}
